/**
 * Google protocol buffer utility. 
 */

var proto = {};
var globalConfigs = require("../globalConfigs.js");

function loadProtoFiles() {
	"use strict";
	var fs = require("fs");
	var Schema = require("protobuf").Schema;

	var cmdUri = globalConfigs.protoDir + "ocean.desc";
	var schemaObj = new Schema(fs.readFileSync(cmdUri));
	return schemaObj;
}

var schema = loadProtoFiles();
var bcmd = schema["ocean.BCmd"];

proto.parseBasicCmd = function(buffer) {
	"use strict";
	try {
		var bcmdobj = bcmd.parse(buffer);
		return bcmdobj;
	} catch (e) {
		console.error(e);
	}

	return null;
};

function parse(buffer, type) {
	"use strict";
	var fulltype = "ocean." + type;
	var pt = schema[fulltype];
	if (pt === null) {
		console.error("no proto for type:" + fulltype);
	} else {
		try {
			var ptobj = pt.parse(buffer);
			return ptobj;
		} catch (e) {
			console.error(e);
		}
	}
	return null;
}

function serialize(obj, type) {
	"use strict";
	var fulltype = "ocean." + type;
	var pt = schema[fulltype];
	return pt.serialize(obj);
}

function integerSize(integer) {
	"use strict";
	if (integer <= 127) {
		return 1;
	} else if (integer <= 63 * 255) {
		return 2;
	} else if (integer <= 31 * 255 * 255) {
		return 3;
	} else {
		throw "integer tOO large:" + integer;
	}
}

function packInteger(buff, integer) {
	"use strict";
	/*jshint bitwise: false*/
	if (integer <= 127) {
		buff[0] = integer;
		return 1;
	} else if (integer <= 63 * 255) {
		// b:10xx xxxx 
		buff[0] = (0x80 | (integer & 63));
		buff[1] = (integer >> 6);
		return 2;
	} else if (integer <= 31 * 255 * 255) {
		// b:110x xxxx
		buff[0] = (0xc0 | (integer & 31));
		buff[1] = ((integer >> 5) & 0xff);
		buff[2] = (integer >> 13);
		return 3;
	} else {
		throw "integer tOO large:" + integer;
	}
}

proto.pack = function(command, body, type) {
	"use strict";
	var bodybuffer = [];
	if (body) {
		bodybuffer = serialize(body, type);
		command.body = bodybuffer;
	}

	var cmdbuffer = bcmd.serialize(command);
	var cmdSize = cmdbuffer.length;
	var packLength = integerSize(cmdSize);

	var buff = new Buffer(packLength + cmdSize);
	packInteger(buff, cmdSize);
	cmdbuffer.copy(buff, packLength, 0, cmdSize);

	return buff;
};

proto.parse = parse;
module.exports = proto;
